import java.awt.image.BufferedImage;
import java.util.StringTokenizer;

public abstract class SpaceObject
{
	public static final int SCREEN_WIDTH = AsteroidsGame.GAME_WIDTH;
	public static final int SCREEN_HEIGHT = AsteroidsGame.GAME_HEIGHT;
	
	public static enum CollisionType {POINT, CIRCLE, TRIANGLE, NONE};
	
	public double x,y;
	
	public SpaceObject(int x, int y)
	{
		this.x = x;
		this.y = y;
	}
	
	public SpaceObject()
	{
		// loadState should be called by derived constructor
	}
	
	public double getX() { return x; }
	public double getY() { return y; }
	
	public abstract BufferedImage getImage();
	
	public abstract CollisionType collisionType();
	// expected to return data appropriate for its collision type:
	//  point: (x, y)
	//  triangle: (x1, y1, x2, y2, x3, y3)
	//  circle: (x, y, r)
	public abstract double[] collisionData(); 
	
	// function called when a collision happens
	// should return true if the hit causes this object to be deleted
	public abstract boolean hit(SpaceObject by);
	
	// load and save state from a saved game
	// the string is expected to be a single line, terminated by a newline
	protected void loadState(StringTokenizer strtok) throws NumberFormatException
	{
		x = Double.parseDouble(strtok.nextToken());
		y = Double.parseDouble(strtok.nextToken());
	}
	protected String saveState()
	{
		return String.format("%f %f ", x, y);
	}
	
	
	// sqaure distance is needed in some cases, and it's faster than
	// using a square root here
	public double squareDistance(SpaceObject other)
	{
		return (other.getX() - x)*(other.getX() - x) +
				(other.getY() - y)*(other.getY() - y);
	}
	
	// slower, but not used as often
	public double distanceWithWrap(SpaceObject other)
	{
		double dx = Math.abs(other.x - x);
		double dy = Math.abs(other.y - y);
		if(dx > AsteroidsGame.GAME_WIDTH/2)
			dx = AsteroidsGame.GAME_WIDTH - dx;
		if(dy > AsteroidsGame.GAME_HEIGHT/2)
			dy = AsteroidsGame.GAME_HEIGHT - dy;
		return Math.sqrt(dx*dx + dy*dy);
	}
	
	public double direction(SpaceObject other)
	{
		return Math.atan2(other.getY() - y, other.getX() - x);
	}
	
	// schedule this object for deletion
	// we can't just delete it directly from gameObjects, since deleting
	// will usually happen while gameObjects is being iterated over
	public void delete()
	{
		AsteroidsGame.game.deleteObject(this);
	}
}
